﻿\subsection{Загрузка 32-битной константы в регистр}
\label{MIPS_big_constants}

\begin{lstlisting}[style=customc]
unsigned int f()
{
	return 0x12345678;
};
\end{lstlisting}

В MIPS, так же как и в ARM, все инструкции имеют размер 32 бита, так что невозможно
закодировать 32-битную константу в инструкцию.

\myindex{MIPS!\Instructions!LI}
\myindex{MIPS!\Instructions!ORI}
Так что приходится делать это используя по крайней мере две инструкции:
первая загружает старшую часть 32-битного числа и вторая применяет операцию \q{ИЛИ},
эффект от которой в том, что она просто выставляет младшие 16 бит целевого регистра:

\begin{lstlisting}[caption=GCC 4.4.5 -O3 (\assemblyOutput),style=customasmMIPS]
        li      $2,305397760  # 0x12340000
        j       $31
        ori     $2,$2,0x5678 ; branch delay slot
\end{lstlisting}

\IDA знает о таких часто встречающихся последовательностях, так что для удобства, 
она показывает последнюю инструкцию \INS{ORI} как псевдоинструкцию \INS{LI},
которая якобы загружает полное 32-битное значение в регистр \$V0.

\myindex{MIPS!\Instructions!LUI}

\begin{lstlisting}[caption=GCC 4.4.5 -O3 (IDA),style=customasmMIPS]
         lui     $v0, 0x1234
         jr      $ra
         li      $v0, 0x12345678 ; branch delay slot
\end{lstlisting}

В выводе на ассемблере от GCC есть псевдоинструкция \INS{LI}, но на самом деле, 
там \INS{LUI} (\q{Load Upper Immediate}), загружающая 16-битное значение в старшую часть регистра.

Посмотрим в выводе \IT{objdump}:

\begin{lstlisting}[caption=objdump,style=customasmMIPS]
00000000 <f>:
   0:   3c021234        lui     v0,0x1234
   4:   03e00008        jr      ra
   8:   34425678        ori     v0,v0,0x5678
\end{lstlisting}

\subsubsection{Загрузка 32-битной глобальной переменной в регистр}

\begin{lstlisting}[style=customc]
unsigned int global_var=0x12345678;

unsigned int f2()
{
        return global_var;
};
\end{lstlisting}

\myindex{MIPS!\Instructions!LW}

Тут немного иначе: \INS{LUI} загружает старшие 16 бит из \IT{global\_var} в \$2 (или \$V0) и затем \INS{LW} загружает младшие
16 бит суммируя их с содержимым \$2:

\begin{lstlisting}[caption=GCC 4.4.5 -O3 (\assemblyOutput),style=customasmMIPS]
f2:
        lui     $2,%hi(global_var)
        lw      $2,%lo(global_var)($2)
        j       $31
        nop	; branch delay slot

	...

global_var:
        .word   305419896
\end{lstlisting}

\IDA знает о часто применяемой паре инструкций \INS{LUI}/\INS{LW}, так что она объединяет их в одну инструкцию \INS{LW}:

\begin{lstlisting}[caption=GCC 4.4.5 -O3 (IDA),style=customasmMIPS]
_f2:
                lw      $v0, global_var
                jr      $ra
                or      $at, $zero	; branch delay slot

		...

                .data
                .globl global_var
global_var:     .word 0x12345678         # DATA XREF: _f2
\end{lstlisting}

Вывод \IT{objdump} почти такой же, как ассемблерный вывод GCC.
Посмотрим также релоки в объектном файле:

\begin{lstlisting}[caption=objdump,style=customasmMIPS]
objdump -D filename.o

...

0000000c <f2>:
   c:   3c020000        lui     v0,0x0
  10:   8c420000        lw      v0,0(v0)
  14:   03e00008        jr      ra
  18:   00200825        move    at,at	; branch delay slot
  1c:   00200825        move    at,at

Disassembly of section .data:

00000000 <global_var>:
   0:   12345678        beq     s1,s4,159e4 <f2+0x159d8>

...

objdump -r filename.o

...

RELOCATION RECORDS FOR [.text]:
OFFSET   TYPE              VALUE
0000000c R_MIPS_HI16       global_var
00000010 R_MIPS_LO16       global_var

...

\end{lstlisting}

Можем увидеть, что адрес \IT{global\_var} будет записываться прямо в инструкции \INS{LUI} и \INS{LW} во время загрузки исполняемого
файла:
старшая 16-битная часть \IT{global\_var} записывается в первую инструкцию (\INS{LUI}), младшая 16-битная часть ---
во вторую (\INS{LW}).

